package org.dwpd.service.message.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.BooleanUtil;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.dwpd.domain.common.Result;
import org.dwpd.domain.user.UserDTO;
import org.dwpd.domain.user.UserInfo;
import org.dwpd.mapper.message.MessageMapper;
import org.dwpd.mapper.user.UserMapper;
import org.dwpd.domain.message.Message;
import org.dwpd.domain.message.MessageEsInfo;
import org.dwpd.domain.message.MessageInfo;
import org.dwpd.domain.inbox.UserMessageRequest;
import org.dwpd.domain.inbox.UserMessageResponse;
import org.dwpd.service.message.MessageService;
import org.dwpd.utils.UserHolder;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static org.dwpd.domain.common.Code.RESULT_CODE_FAIL;
import static org.dwpd.domain.common.Code.RESULT_CODE_UNLOGIN;
import static org.dwpd.utils.RedisConstants.*;

@Service
@Slf4j
public class MessageServiceImpl implements MessageService {

    @Autowired
    private MessageMapper messageMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RestHighLevelClient client;

    @Override
    public Result addMessage(Message message, HttpServletRequest request) {

        // 1. 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        // 2. 判断用户是否在黑名单中
        Integer flag = userMapper.getUserFlagInBlack(userId);
        if (flag == 1) {
            return Result.fail(RESULT_CODE_FAIL, "用户已进入黑名单，无法发布任务");
        }
        message.setUserId(userId);
        log.info("添加新的用户帖子：{}", message);
        if (message.getUserId() == null || message.getStartPoint() == null || message.getEndPoint() == null || message.getStartTime() == null || message.getPeopleNum() == null) {
            log.info("用户输入参数不完整");
            return Result.fail(RESULT_CODE_FAIL, "用户输入参数不完整，请重新输入");
        }
        message.setStartTime(message.getStartTime());
        log.info("message: {}", message);

        // 3. 将数据存入数据库中
        messageMapper.addMessage(message);

        // 4. 将数据存入缓存中 `message:userId:messageId` 中
        MessageInfo messageInfo = addRedisMessageInfo(message, request);

        // 5. 创建缓存 `lock:message:messageId` 存放帖主id，后续该缓存用来存放上座用户0|,
        stringRedisTemplate.opsForSet().add(LOCK_MESSAGE_KEY + messageInfo.getMessageId(), messageInfo.getUserId().toString());

        // 6. 添加数据到索引库
        addEsMessageInfo(messageInfo);

        // 7. 返回结果
        return Result.success("添加用户帖成功");
    }



    @Override
    public Result getAllMessageById() {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        log.info("获取用户id为:{} 的所有已发帖信息", userId);
        List<Message> result = messageMapper.selectAllMessageById(userId);
        if (result == null || result.isEmpty()) {
            return Result.fail(RESULT_CODE_FAIL, "获取所有已发帖失败");
        }
        return Result.success(result);
    }

    @Override
    public Result getMessageDetailById(Integer messageId) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        // 判断参数是否正确
        if (messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        log.info("获取用户帖为:{} 的详细信息", messageId);
        // 从缓存中获取信息，并进行判断
        Map<Object, Object> messageMap = stringRedisTemplate.opsForHash().entries(MESSAGE_KEY + messageId);
        MessageInfo messageInfo;
        // 1. 判断帖子是否过期
        if (messageMap.isEmpty()) {
            // 从数据库获取
            Message message = messageMapper.selectMessageDetailById(messageId);
            if (message == null) {
                // 若数据库也查询不到，则帖子不存在或者已过期
                return Result.fail(RESULT_CODE_FAIL, "帖子已过期");
            }
            // 刷新缓存
            messageInfo = addRedisMessageInfo(message, null);
            stringRedisTemplate.opsForSet().add(LOCK_MESSAGE_KEY + messageInfo.getMessageId(), messageInfo.getUserId().toString());
        }
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DATE, 1);
        // 2. 帖子未过期，缓存中能查询到，则查看是否上锁
        messageInfo = BeanUtil.fillBeanWithMap(messageMap, new MessageInfo(), false);
        if (messageInfo.getLockFlag() != null && messageInfo.getLockFlag().equals(1)) {
            // 帖子已上锁，则只有上座的人以及帖主才能查看信息
            // 2.1 判断该用户是否在上座人群中
            Boolean judge = stringRedisTemplate.opsForSet().isMember(LOCK_MESSAGE_KEY + messageId, userId.toString());
            if (BooleanUtil.isFalse(judge)) {
                // 若当前用户不在上座人群，则无法进入详情页
                return Result.fail(RESULT_CODE_FAIL, "该帖已上锁，当前用户无法进入");
            }
        }
        log.info("帖子未上锁: messageInfo-{}", messageInfo);
        // 3.帖子未过期 或 用户在上座人群中，返回缓存中的数据
        return Result.success(messageInfo);
    }

    @Override
    public Result updateAccomplish(Integer messageId) {
        try {
            // 判断用户是否登录
            UserDTO user = UserHolder.getUser();
            if (user == null) {
                return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
            }
            Integer userId = user.getUserId();
            // 参数判断
            if (messageId == null || messageId <= 0) {
                return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
            }
            log.info("帖子id为：{} 的任务已完成", messageId);

            // 数据库修改数据
            Integer total = messageMapper.updateAccomplish(messageId);
            if (total == null || total <= 0) {
                return Result.fail(RESULT_CODE_FAIL, "修改任务为完成状态失败");
            }

            // 数据库乐拼积分增加
            userMapper.addUserScore(userId);

            // 缓存删除数据
            stringRedisTemplate.delete(MESSAGE_KEY + messageId);

            // 索引库删除数据
            DeleteRequest deleteRequest = new DeleteRequest("message", messageId.toString());
            client.delete(deleteRequest, RequestOptions.DEFAULT);

            // 封装请求信息并返回结果
            // 5. 封装锁帖信息并返回
            // 获取上座用户Id信息
            String ids = messageMapper.getOnSeatUsersByMessageId(messageId);
            UserMessageRequest userMessageRequest = getUserMessageRequest("accomplishMessage", messageId, 0, userId, "", ids);
            return Result.success(userMessageRequest);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result deleteMessage(Integer messageId) {
        try {
            // 判断用户是否登录
            UserDTO user = UserHolder.getUser();
            if (user == null) {
                return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
            }
            // 判断参数是否正确
            if (messageId == null || messageId <= 0) {
                return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
            }
            log.info("删除帖子, id: {}", messageId);
            // 数据库删除数据
            messageMapper.deleteMessage(messageId);

            // 缓存删除数据
            stringRedisTemplate.delete(MESSAGE_KEY + messageId);

            // 索引库删除数据
            DeleteRequest deleteRequest = new DeleteRequest("message", messageId.toString());
            client.delete(deleteRequest, RequestOptions.DEFAULT);

            return Result.success("删除用户贴成功");

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result updateMessage(Message message) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        message.setUserId(userId);
        log.info("修改用户帖信息为：{}", message);
        /*需要对当前帖子用户id与登录用户id进行对比，不同则无法修改*/
        if (message.getUserId() != userId) {
            return Result.fail(RESULT_CODE_FAIL, "当前用户非任务发布者，无法修改此任务");
        }
        // 修改数据库中的数据
        Integer total = messageMapper.updateMessage(message);
        if (total == null || total <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "信息修改失败");
        }

        // 修改缓存中的数据
        MessageInfo messageInfo = new MessageInfo();
        BeanUtils.copyProperties(message, messageInfo);
        updateRedisInfo(messageInfo, user);

        // 修改索引库中的数据
        addEsMessageInfo(messageInfo);

        return Result.success("修改任务成功");
    }

    @Override
    public Result updateMessageOverTime() {

        try {
            // 判断用户是否登录
            UserDTO user = UserHolder.getUser();
            if (user == null) {
                return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
            }
            Integer userId = user.getUserId();

            // 1. 先获取当前用户所有的超时(系统时间超过出发时间十二小时)帖子id
            List<Integer> ids = messageMapper.selectMessageOverTime(userId);
            if (ids == null || ids.isEmpty()) {
                return Result.success("结束超时任务: 0");
            }
            // 2. 修改这些超时帖子的任务进度为已结束
            // 2.1 帖子未上锁 -> 超时任务
            Integer overTimeNums = messageMapper.updateMessageOverTime(ids);
            // 2.2 帖子已上锁 -> 完成任务
            Integer accomplishNums = messageMapper.updateMessageAccomplish(ids);
            // 2.3 修改用户信誉分
            userMapper.updateUserGrade(overTimeNums, accomplishNums, userId);
            // 3. 索引库删除数据
            BulkRequest bulkRequest = new BulkRequest();
            ids.stream().map(String::valueOf).toList().forEach(id -> bulkRequest.add(new DeleteRequest("message", id)));
            client.bulk(bulkRequest, RequestOptions.DEFAULT);
            return Result.success("结束超时任务 -> " + "已过期: " + overTimeNums + " 已完成: " + accomplishNums);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result getAllMessage(Integer typeId) {

        log.info("获取所有用户帖，参数类型：{}", typeId);
        if (typeId == null || typeId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        // 根据参数类型进行数据获取
        List<Message> list = null;
        if (typeId == 1) {
            // 获取全部用户帖
            list = messageMapper.selectAllMessage();
        }
        else if (typeId == 2) {
            // 获取最新发布的用户帖
            list = messageMapper.selectAllNewCreateMessage();
        }
        else if (typeId == 3) {
            // 获取正在进行任务的用户帖
            list = messageMapper.selectAllNotAccomplishMessage();
        }
        if (list == null || list.isEmpty()) {
            return Result.fail(RESULT_CODE_FAIL, "获取用户帖失败");
        }
        return Result.success(list);
    }

    @Override
    public void addRequestMessage(UserMessageResponse resp) {
        messageMapper.addRequestMessage(resp);
    }

    @Override
    public void addAgreeMessage(UserMessageResponse resp) {
        messageMapper.addAgreeMessage(resp);
    }

    @Override
    public void addRejectMessage(UserMessageResponse resp) {
        messageMapper.addRejectMessage(resp);
    }

    @Override
    public Result lockMessage(Integer messageId) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        log.info("用户-{} 对 帖子-{} 进行锁帖", userId, messageId);

        // 1. 修改当前帖子在数据库中的 lock_flag 为1，表示锁帖
        Integer total = messageMapper.lockMessage(messageId, userId);
        if (total == null || total <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "用户锁帖失败");
        }
        // 2. 修改缓存 message:messageId 中的 lockFlag 为1
        stringRedisTemplate.opsForHash().put(MESSAGE_KEY + messageId, "lockFlag", "1");
        // 3. 创建数据库表 lock_message，将缓存 lock:message:messageId 中的数据记录到表中
        Set<String> members = stringRedisTemplate.opsForSet().members(LOCK_MESSAGE_KEY + messageId);
        // 移除帖主本身
        members.remove(userId.toString());
        Integer peopleNum = members.size();
        String peopleList = StringUtil.join(members.toArray(), ",");
        total = messageMapper.addLockUserMessage(messageId, userId, peopleNum, peopleList);
        if (total == null || total <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "用户锁帖失败");
        }
        // 4. 修改索引表
        // 4.1 从缓存中获取信息，并进行判断
        Map<Object, Object> messageMap = stringRedisTemplate.opsForHash().entries(MESSAGE_KEY + messageId);
        // 4.2 判断帖子是否过期
        if (messageMap.isEmpty()) {
            // 缓存中帖子不存在，表示过期，返回空
            return Result.fail(RESULT_CODE_FAIL, "帖子已过期");
        }
        // 2. 帖子未过期，转换类型
        MessageInfo messageInfo = BeanUtil.fillBeanWithMap(messageMap, new MessageInfo(), false);
        addEsMessageInfo(messageInfo);

        // 4. 将帖子信息保存到上座用户的收件箱中
        for (String seatUserId : members) {
            stringRedisTemplate.opsForZSet().add(INBOX_USER_KEY + seatUserId, messageId.toString(), System.currentTimeMillis());
        }

        // 5. 封装锁帖信息并返回
        UserMessageRequest userMessageRequest = getUserMessageRequest("lockMessage", messageId, 0, userId, "", peopleList);
        return Result.success(userMessageRequest);
    }

    @Override
    public List<MessageInfo> getMessageByIds(List<Integer> ids) {
        return messageMapper.getMessageByIds(ids);
    }

    @Override
    @Transactional
    public void accomplishAllOverTimeTask() {

        try {
            // 1. 获取所有超时任务
            List<Integer> ids = messageMapper.selectAllOverTimeTaskIds();
            if (ids == null || ids.isEmpty()) {
                log.info("无超时任务");
                return;
            }
            // 2. 修改任务状态
            // 2.1 未上锁 -> 已过期
            Integer overTimeNums = messageMapper.updateMessageOverTime(ids);
            // 2.2 已上锁 -> 已完成
            Integer accomplishNum = messageMapper.updateMessageAccomplish(ids);
            log.info("定期修改修改超时任务 -> ids: {} 已过期: {} 已完成: {}", ids, overTimeNums, accomplishNum);
            // 3. 判断用户信誉分状态并进行修改
            Integer updateNum = userMapper.updateBlackFlag();
            log.info("定期修改用户信誉分状态 -> 加入黑名单人数: {}", updateNum);
            // 4. 索引库删除数据
            BulkRequest bulkRequest = new BulkRequest();
            ids.stream().map(String::valueOf).toList().forEach(id -> bulkRequest.add(new DeleteRequest("message", id)));
            client.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void addInformMessage(UserMessageResponse resp) {
        messageMapper.addInformMessage(resp);
    }

    @Override
    public Result getOnSeatUsersByMessageId(Integer messageId) {
        String ids = messageMapper.getOnSeatUsersByMessageId(messageId);
        return Result.success(ids);
    }

    @Override
    public Result getUserRootFlagInMessage(Integer messageId) {
        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        Integer rootUser = messageMapper.getUserIdByMessageId(messageId);
        if (rootUser == null) {
            return Result.fail(-1, "当前用户帖不存在");
        }
        if (rootUser.equals(userId)) {
            return Result.success(true);
        }
        return Result.success(false);
    }

    @Override
    public Result getOnSeatHistoryByUserId(Integer userId) {
        // 1. 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(-2, "用户未登录");
        }
        // 2. 查询收件箱 ZREVRANGEBYSCORE key Max Min limit offset count
        Long size = stringRedisTemplate.opsForZSet().size(INBOX_USER_KEY + userId);
        // 非空判断
        if (size == null || size <= 0) {
            return Result.success(Collections.emptyList());
        }
        Set<String> sets = stringRedisTemplate.opsForZSet().reverseRange(INBOX_USER_KEY + userId, 0, size + 1);
        List<Integer> ids = sets.stream().map(Integer::valueOf).collect(Collectors.toList());
        // 3. 返回ids查询结果并返回
        List<MessageInfo> messageInfos = messageMapper.getMessageByIds(ids);
        return Result.success(messageInfos);
    }

    @Override
    public Result getMessageDetailByUser(Integer messageId) {
        // 参数判断
        if (messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        log.info("获取用户帖为:{} 的详细信息", messageId);

        MessageInfo messageInfo = messageMapper.getMessageDetailById(messageId);
        return Result.success(messageInfo);
    }

    @Override
    public Result addSeat(Integer messageId) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        if (messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        log.info("用户 {} 申请上座, 目标帖：{}", userId, messageId);
        // 判断用户是否在黑名单中
        Integer flag = userMapper.getUserFlagInBlack(userId);
        if (flag == 1) {
            return Result.fail(RESULT_CODE_FAIL, "用户已进入黑名单，无法上座");
        }
        // 1-3 是为了避免在座位还未满的时候有多个用户向帖主发起上座请求，而帖主都同意了会出现多上座的情况
        Result seatFull = isSeatFull(messageId);
        if (seatFull != null) return seatFull;

        // 3.2 若不一致，表示上座人数未满，用户可以向帖主发送上座请求(下述为请求参数) -> 等待帖主同意上座请求
        String hostUserId = (String) stringRedisTemplate.opsForHash().get(MESSAGE_KEY + messageId, "userId");
        if (hostUserId == null) {
            hostUserId = "0";
        }
        // 4. 封装请求并返回结果
        UserMessageRequest userMessageRequest = getUserMessageRequest("requestMessage", messageId, Integer.valueOf(hostUserId), userId, "", "");
        return Result.success(userMessageRequest);
    }


    @Override
    public Result agreeUserSeat(Integer userId, Integer messageId) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer hostUserId = user.getUserId();
        // 参数判断
        if (userId == null || userId <= 0 || messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        // 1-3 是为了避免在座位还未满的时候有多个用户向帖主发起上座请求，而帖主都同意了会出现多上座的情况
        Result seatFull = isSeatFull(messageId);
        if (seatFull != null) return seatFull;
        // 4. 修改请求数据库中的信息，agree_flag 设为 1
        Integer total = messageMapper.updateAgree(userId, messageId);
        if (total == null || total <= 0) {
            // 避免重复上座的情况
            return Result.fail(RESULT_CODE_FAIL, "上座失败");
        }
        // 5. 将请求用户添加到缓存 lock:message:messageId 中
        stringRedisTemplate.opsForSet().add(LOCK_MESSAGE_KEY + messageId, userId.toString());
        // 6. 返回结果
        UserMessageRequest userMessageRequest = getUserMessageRequest("agreeMessage", messageId, userId, hostUserId, "", "");
        return Result.success(userMessageRequest);
    }

    @Override
    public Result removeUserSeat(Integer userId, Integer messageId) {
        // 参数判断
        if (userId == null || userId <= 0 || messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        // 将用户从缓存 lock:message:messageId 中移除
        Long remove = stringRedisTemplate.opsForSet().remove(LOCK_MESSAGE_KEY + messageId, userId.toString());
        if (remove == null || remove <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "移除座位失败!");
        }
        return Result.success("移除座位成功!");
    }

    @Override
    public Result userLeaveSeat(Integer messageId) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer userId = user.getUserId();
        // 判断参数是否正确
        if (messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        log.info("用户 {} 离座, 目标帖：{}", userId, messageId);
        // 判断当前用户是否为帖主本身，若为帖主本身则无法离座
        String messageUserIdStr = (String) stringRedisTemplate.opsForHash().get(MESSAGE_KEY + messageId, "userId");
        Integer messageUserId = Integer.valueOf(messageUserIdStr);
        if (userId == messageUserId) {
            return Result.fail(RESULT_CODE_FAIL, "发布者无法离座");
        }
        // 将用户从缓存 lock:message:messageId 中移除
        Long remove = stringRedisTemplate.opsForSet().remove(LOCK_MESSAGE_KEY + messageId, userId.toString());
        if (remove == null || remove <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "用户离座失败");
        }
        return Result.success("用户离座成功");
    }
    @Override
    public Result rejectUserSeat(Integer userId, Integer messageId) {

        // 判断用户是否登录
        UserDTO user = UserHolder.getUser();
        if (user == null) {
            return Result.unlogin(RESULT_CODE_UNLOGIN, "用户未登录");
        }
        Integer hostUserId = user.getUserId();
        // 参数判断
        if (userId == null || userId <= 0 || messageId == null || messageId <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "请求参数错误");
        }
        // 操作数据库
        Integer total =  messageMapper.updateReject(userId, messageId);
        if (total == null || total <= 0) {
            return Result.fail(RESULT_CODE_FAIL, "拒绝用户上座失败");
        }
        // 封装请求信息返回结果
        UserMessageRequest userMessageRequest = getUserMessageRequest("rejectMessage", messageId, userId, hostUserId, "", "");
        return Result.success(userMessageRequest);
    }

    private void addEsMessageInfo(MessageInfo messageInfo) {
        try {
            // 5.1 准备Request对象
            MessageEsInfo messageEsInfo = new MessageEsInfo(messageInfo);
            messageEsInfo.setLevel(userMapper.selectUserDetailById(messageInfo.getUserId()).getLevel());
//            BeanUtils.copyProperties(messageInfo, messageEsInfo);
            IndexRequest esRequest = new IndexRequest("message").id(messageEsInfo.getMessageId().toString());
            // 5.2 准备JSON文档
            esRequest.source(JSON.toJSONString(messageEsInfo), XContentType.JSON);
            // 5.3 发送请求
            client.index(esRequest, RequestOptions.DEFAULT);
            log.info("索引文档添加成功!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private MessageInfo addRedisMessageInfo(Message message, HttpServletRequest request) {

        // 3.1 将用户基本信息存入 message 对象中
        if (request != null) {
            String token = request.getHeader("token");
            fillMessage(message, token);
        }
        // 3.2 创建 messageInfo 对象，并将其存入缓存
        MessageInfo messageInfo = new MessageInfo();
        BeanUtils.copyProperties(message, messageInfo);
        messageInfo.setAccomplishFlag(0);
        String key = MESSAGE_KEY + messageInfo.getMessageId();
        Map<String, Object> messageMap = BeanUtil.beanToMap(messageInfo, new HashMap<>(), CopyOptions.create().setIgnoreNullValue(true)
                .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        stringRedisTemplate.opsForHash().putAll(key, messageMap);

        // 3.3 设置缓存过期时间为 出发时间的24h后
        Long hour = getTimeHour(messageInfo.getStartTime());
        stringRedisTemplate.expire(key, hour + MESSAGE_TTL, TimeUnit.HOURS);
        return messageInfo;
    }

    private Long getTimeHour(String startTime) {

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        LocalDateTime T2 = LocalDateTime.parse(startTime, formatter);
        LocalDateTime T1 = LocalDateTime.now();
        Duration time = Duration.between(T1, T2);
        long hour = time.toHours();
        return hour;
    }

    private void fillMessage(Message message, String token) {
        // 从缓存中获取当前登录用户的信息
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(LOGIN_USER_KEY + token);
        UserInfo userInfo = BeanUtil.fillBeanWithMap(userMap, new UserInfo(), false);
        message.setUserName(userInfo.getUserName());
        message.setUserImage(userInfo.getUserImage());
        message.setLockFlag(0);
        message.setCreateTime(new Date(System.currentTimeMillis()));
        message.setUpdateTime(new Date(System.currentTimeMillis()));
    }

    private void updateRedisInfo(MessageInfo messageInfo, UserDTO user) {

        try {
            // 1. 创建 messageInfo 对象，并将其存入缓存
            String key = MESSAGE_KEY + messageInfo.getMessageId();
            messageInfo.setUserName(user.getUserName());
            messageInfo.setUserImage(user.getUserImage());
            messageInfo.setLockFlag(0);
            messageInfo.setUpdateTime(new Date(System.currentTimeMillis()));
//            messageInfo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(messageInfo.getCreateTime()));
            messageInfo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(String.valueOf(stringRedisTemplate.opsForHash().get(key, "createTime"))));

            Map<String, Object> messageMap = BeanUtil.beanToMap(messageInfo, new HashMap<>(), CopyOptions.create().setIgnoreNullValue(true)
                    .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
            stringRedisTemplate.opsForHash().putAll(key, messageMap);

            // 1.2 设置缓存过期时间为 出发时间的24h后
            Long hour = getTimeHour(messageInfo.getStartTime());
            stringRedisTemplate.expire(key, hour + MESSAGE_TTL, TimeUnit.HOURS);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

    }

    private UserMessageRequest getUserMessageRequest(
            String messageType, Integer messageId, Integer acceptUserId ,Integer userId, String content, String ids) {
        UserMessageRequest userMessageRequest = new UserMessageRequest();
        userMessageRequest.setType(messageType);
        userMessageRequest.setMessageId(messageId);
        userMessageRequest.setAcceptUserId(acceptUserId);
        userMessageRequest.setUserId(userId);
        userMessageRequest.setContent(content);
        userMessageRequest.setIds(ids);
        userMessageRequest.setToken("");
        return userMessageRequest;
    }

    private Result isSeatFull(Integer messageId) {
        // 1. 获取当前上座人数, 需要-1因为包括了帖主自己也在这个集合中
        Set<String> members = stringRedisTemplate.opsForSet().members(LOCK_MESSAGE_KEY + messageId);
        String size = String.valueOf(members.size() - 1);
        // 2. 获取需求拼车人数
        String num = (String) stringRedisTemplate.opsForHash().get(MESSAGE_KEY + messageId, "peopleNum");
        // 3. 判断大小是否一致
        if (num == null) {
            return Result.fail(RESULT_CODE_FAIL, "上座失败！");
        }
        if (num.equals(size)) {
            // 3.1 若一致，表示上座人数已满，用户无法再进行上座
            return Result.fail(RESULT_CODE_UNLOGIN, "上座人数已满，用户无法上座!");
        }
        return null;
    }
}
